package com.sc.util.ChanPay.pay;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.lang.StringUtils;
import com.sc.util.ChanPay.util.HttpProtocolHandler;
import com.sc.util.ChanPay.util.HttpRequest;
import com.sc.util.ChanPay.util.HttpResponse;
import com.sc.util.ChanPay.util.HttpResultType;
import com.sc.util.ChanPay.util.MD5;
import com.sc.util.ChanPay.util.RSA;
import com.sc.util.adapter.ConfigBeanAdapter;

/**
 * 畅捷通正式环境微信、支付宝扫码支付工具类
 */
public class SweepPay {

	/** 商户号 */
	public static final String CHANPAY_PARTNER_ID = ConfigBeanAdapter.chanpay_partner_id;


	/**快捷网银异步回调地址 */
//	public static final String notify_url =ConfigBeanAdapter.notify_url;
	
	/** 微信appid **/
	public static final String wx_appId= ConfigBeanAdapter.wx_appId;
	
	/** 支付宝appid **/
	public static final String zfb_appId= ConfigBeanAdapter.zfb_appId;
	
	 /**
     *  畅捷支付平台公钥
     */
    private static String MERCHANT_PUBLIC_KEY = ConfigBeanAdapter.merchant_public_key;
    /**
     *  商户私钥
     */
    private static String MERCHANT_PRIVATE_KEY = ConfigBeanAdapter.merchant_private_key;
	/**
	 * 编码类型
	 */
	private static String charset = "UTF-8";

	/**
	 * 获取SimpleDateFormat
	 * 
	 * @param parttern
	 *            日期格式
	 * @return SimpleDateFormat对象
	 * @throws RuntimeException
	 *             异常：非法日期格式
	 */
	private static SimpleDateFormat getDateFormat(String parttern)
			throws RuntimeException {
		return new SimpleDateFormat(parttern);
	}

	/**
	 * 建立请求，以模拟远程HTTP的POST请求方式构造并获取钱包的处理结果
	 * 如果接口中没有上传文件参数，那么strParaFileName与strFilePath设置为空值 如：buildRequest("",
	 * "",sParaTemp)
	 *
	 * @param strParaFileName
	 *            文件类型的参数名
	 * @param strFilePath
	 *            文件路径
	 * @param sParaTemp
	 *            请求参数数组
	 * @return 钱包处理结果
	 * @throws Exception
	 */
	public static String buildRequest(Map<String, String> sParaTemp,
			String signType, String key, String inputCharset, String gatewayUrl)
			throws Exception {
		// 待请求参数数组
		Map<String, String> sPara = buildRequestPara(sParaTemp, signType, key,
				inputCharset);
		HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler
				.getInstance();
		HttpRequest request = new HttpRequest(HttpResultType.BYTES);
		// 设置编码集
		request.setCharset(inputCharset);
		request.setMethod(HttpRequest.METHOD_POST);
		request.setParameters(generatNameValuePair(
				createLinkRequestParas(sPara), inputCharset));
		request.setUrl(gatewayUrl);
		HttpResponse response = httpProtocolHandler
				.execute(request, null, null);
		if (response == null) {
			return null;
		}
		String strResult = response.getStringResult();
		return strResult;
	}
	
	/**
	 * 建立请求，以模拟远程HTTP的POST请求方式构造并获取钱包的处理结果
	 * 如果接口中没有上传文件参数，那么strParaFileName与strFilePath设置为空值 如：buildRequest("",
	 * "",sParaTemp)
	 *
	 * @param strParaFileName
	 *            文件类型的参数名
	 * @param strFilePath
	 *            文件路径
	 * @param sParaTemp
	 *            请求参数数组
	 * @return 钱包处理结果
	 * @throws Exception
	 */
	public static Object buildRequests(Map<String, String> sParaTemp,
			String signType, String key, String inputCharset, String gatewayUrl)
			throws Exception {
		// 待请求参数数组
		Map<String, String> sPara = buildRequestPara(sParaTemp, signType, key,
				inputCharset);
		HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler
				.getInstance();
		HttpRequest request = new HttpRequest(HttpResultType.BYTES);
		// 设置编码集
		request.setCharset(inputCharset);
		request.setMethod(HttpRequest.METHOD_POST);
		request.setParameters(generatNameValuePair(
				createLinkRequestParas(sPara), inputCharset));
		request.setUrl(gatewayUrl);
		HttpResponse response = httpProtocolHandler
				.execute(request, null, null);
		if (response == null) {
			return null;
		}

		byte[] byteResult = response.getByteResult();
		if (byteResult.length > 1024) {
			return byteResult;
		} else {
			return response.getStringResult();
		}

	}


	/**
	 * MAP类型数组转换成NameValuePair类型
	 *
	 * @param properties
	 *            MAP类型数组
	 * @return NameValuePair类型数组
	 */
	private static NameValuePair[] generatNameValuePair(
			Map<String, String> properties, String charset) throws Exception {
		NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
		int i = 0;
		for (Map.Entry<String, String> entry : properties.entrySet()) {
			// nameValuePair[i++] = new NameValuePair(entry.getKey(),
			// URLEncoder.encode(entry.getValue(),charset));
			nameValuePair[i++] = new NameValuePair(entry.getKey(),
					entry.getValue());
		}
		return nameValuePair;
	}

	/**
	 * 生成要请求给钱包的参数数组
	 * 
	 * @param sParaTemp
	 *            请求前的参数数组
	 * @param signType
	 *            RSA
	 * @param key
	 *            商户自己生成的商户私钥
	 * @param inputCharset
	 *            UTF-8
	 * @return 要请求的参数数组
	 * @throws Exception
	 */
	public static Map<String, String> buildRequestPara(
			Map<String, String> sParaTemp, String signType, String key,
			String inputCharset) throws Exception {
		// 除去数组中的空值和签名参数
		Map<String, String> sPara = paraFilter(sParaTemp);
		// 生成签名结果
		String mysign = "";
		if ("MD5".equalsIgnoreCase(signType)) {
			mysign = buildRequestByMD5(sPara, key, inputCharset);
		} else if ("RSA".equalsIgnoreCase(signType)) {
			mysign = buildRequestByRSA(sPara, key, inputCharset);
		}
		// 签名结果与签名方式加入请求提交参数组中
		System.out.println("sign:" + mysign);
		sPara.put("Sign", mysign);
		sPara.put("SignType", signType);

		return sPara;
	}

	/**
	 * 生成MD5签名结果
	 *
	 * @param sPara
	 *            要签名的数组
	 * @return 签名结果字符串
	 */
	public static String buildRequestByMD5(Map<String, String> sPara,
			String key, String inputCharset) throws Exception {
		String prestr = createLinkString(sPara, false); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String mysign = "";
		mysign = MD5.sign(prestr, key, inputCharset);
		return mysign;
	}

	/**
	 * 生成RSA签名结果
	 *
	 * @param sPara
	 *            要签名的数组
	 * @return 签名结果字符串
	 */
	public static String buildRequestByRSA(Map<String, String> sPara,
			String privateKey, String inputCharset) throws Exception {
		String prestr = createLinkString(sPara, false); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String mysign = "";
		mysign = RSA.sign(prestr, privateKey, inputCharset);
		return mysign;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 *
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @param encode
	 *            是否需要urlEncode
	 * @return 拼接后字符串
	 */
	public static Map<String, String> createLinkRequestParas(
			Map<String, String> params) {
		Map<String, String> encodeParamsValueMap = new HashMap<String, String>();
		List<String> keys = new ArrayList<String>(params.keySet());
		String charset = params.get("Charset");
		if (StringUtils.isBlank(charset)) {
			charset = params.get("InputCharset");
		}
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value;
			try {
				value = URLEncoder.encode(params.get(key), charset);
				encodeParamsValueMap.put(key, value);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}

		return encodeParamsValueMap;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 *
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @param encode
	 *            是否需要urlEncode
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params,
			boolean encode) {

		// params = paraFilter(params);

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		String charset = params.get("Charset");
		if (StringUtils.isBlank(charset)) {
			charset = params.get("InputCharset");
		}

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);
			if (encode) {
				try {
					value = URLEncoder.encode(value, charset);
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	/**
	 * 除去数组中的空值和签名参数
	 *
	 * @param sArray
	 *            签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}

		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value == null || value.equals("")
					|| key.equalsIgnoreCase("sign")
					|| key.equalsIgnoreCase("sign_type")) {
				continue;
			}
			// try {
			// value = URLEncoder.encode(value,charset);
			// } catch (UnsupportedEncodingException e) {
			// e.printStackTrace();
			// }
			result.put(key, value);
		}

		return result;
	}

	/**
	 * 向测试服务器发送post请求
	 * 
	 * @param origMap
	 *            参数map
	 * @param charset
	 *            编码字符集
	 * @param MERCHANT_PRIVATE_KEY
	 *            私钥
	 */
	public static String gatewayPost(Map<String, String> origMap, String charset,
			String MERCHANT_PRIVATE_KEY) {
		String resultString="";
		try {
			//String urlStr = "https://tpay.chanpay.com/mag-unify/gateway/receiveOrder.do?"; 
			//String urlStr =  "https://cpay.chanpay.com/mag-unify/gateway/receiveOrder.do?";//测试环境扫码请求网关
		//	String urlStr = "https://pay.chanpay.com/mag-unify/gateway/receiveOrder.do?";  //生产环境地址
            String urlStr = ConfigBeanAdapter.sweepGatewayPost;
			Map<String, String> sPara = buildRequestPara(origMap, "RSA",
					MERCHANT_PRIVATE_KEY, charset);
			System.out.println(urlStr + createLinkString(sPara, true));
			resultString = buildRequest(origMap, "RSA",
					MERCHANT_PRIVATE_KEY, charset, urlStr);
			System.out.println(resultString);
		} catch (Exception e) {
			System.out.println(e);
		}
		return resultString;
	}
	
	/**
	 * 向测试服务器发送post请求
	 * 
	 * @param origMap
	 *            参数map
	 * @param charset
	 *            编码字符集
	 * @param MERCHANT_PRIVATE_KEY
	 *            私钥
	 */
	public Object gatewayPosts(Map<String, String> origMap, String charset,
			String MERCHANT_PRIVATE_KEY) {
		try {
			String urlStr = "https://tpay.chanpay.com/mag-unify/gateway/receiveOrder.do?";
			// String urlStr =
			// "https://cpay.chanpay.com/mag-unify/gateway/receiveOrder.do?";
			Map<String, String> sPara = buildRequestPara(origMap, "RSA",
					MERCHANT_PRIVATE_KEY, charset);
			System.out.println(urlStr + createLinkString(sPara, true));
			Object obj = buildRequests(origMap, "RSA", MERCHANT_PRIVATE_KEY,
					charset, urlStr);
			System.out.println(obj);
			return obj;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}


	/**
	 * 加密，部分接口，有参数需要加密
	 * 
	 * @param src
	 *            原值
	 * @param publicKey
	 *            畅捷支付发送的平台公钥
	 * @param charset
	 *            UTF-8
	 * @return RSA加密后的密文
	 */
	private String encrypt(String src, String publicKey, String charset) {
		try {
			byte[] bytes = RSA.encryptByPublicKey(src.getBytes(charset),
					publicKey);
			return Base64.encodeBase64String(bytes);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 异步通知验签仅供参考
	 */
	public void notifyVerify() {

		String sign = "uERyn9W/b8I88bAVyaXUXXpyw0Ir5D3da6WiO5qrpDrvpgBmDzrYWt2wjZsu6CZdgxZ3+VSdRszrCKJM0UxUGqqKkf0gg90DFlGPMqloZHBzemXSoU2Zz/XYc7/CXWoi3+ZYk43dMhbh/S++RQFBOq+abkiGeD6QNlm4TUiJ7os=";
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("notify_id", "448b7e8b93694e958eae50e295617033");
		paramMap.put("notify_type", "trade_status_sync");
		paramMap.put("notify_time", "20170705104121");
		paramMap.put("_input_charset", "UTF-8");
		paramMap.put("version", "1.0");
		paramMap.put("outer_trade_no", "0001149922237380501132458");
		paramMap.put("inner_trade_no", "101149922237409129479");
		paramMap.put("trade_status", "TRADE_SUCCESS");
		paramMap.put("trade_amount", "0.01");
		paramMap.put("gmt_create", "20170705104121");
		paramMap.put("gmt_payment", "20170705104121");
		// paramMap.put("gmt_close", "");
		paramMap.put("extension", "{}");
		String text = createLinkString(paramMap, false);
		System.out.println("ori_text:" + text);
		try {
			System.out.println(RSA.verify(text, sign, MERCHANT_PUBLIC_KEY,
					charset));
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public void downloadFile(byte[] bt) {
		// 确定写出文件的位置
		File file = new File("C:\\Test.xls");
		// 建立输出字节流
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(file);
			// 用FileOutputStream 的write方法写入字节数组
			fos.write(bt);
			System.out.println("文件下载成功");
			// 为了节省IO流的开销，需要关闭
			if (fos != null) {
				fos.close();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 4.2.1.4. api mag_init_code_pay 微信主扫预下单
	 */
	public static String  wx_mag_init_code_pay(Map<String, String> origMap ) {
		String notify_url = origMap.get("notify_url").toString();
		//String returnUrl = origMap.get("returnUrl").toString();
		String OutTradeNo = origMap.get("OutTradeNo").toString();
		String TradeAmount = origMap.get("TradeAmount").toString();
		String GoodsName = origMap.get("GoodsName").toString();
		String Memo = origMap.get("Memo").toString();
		String TradeMemo = origMap.get("TradeMemo").toString();
		String Subject = origMap.get("Subject").toString();
		String OrderStartTime = origMap.get("OrderStartTime").toString();
		String OrderEndTime = origMap.get("OrderEndTime").toString();
		String SpbillCreateIp = origMap.get("SpbillCreateIp").toString();
		
		Date date = new Date();
		// 基本参数
		origMap.put("Service", "mag_init_code_pay");
		origMap.put("Version", "1.0");
		origMap.put("PartnerId", CHANPAY_PARTNER_ID);//T环境
		origMap.put("_input_charset", charset);
		origMap.put("InputCharset", charset);
		origMap.put("TradeDate", getDateFormat("yyyyMMdd").format(date));
		origMap.put("TradeTime", getDateFormat("HHmmss").format(date));
		// origMap.put("SignType","RSA");
		origMap.put("ReturnUrl","http://3mdrn5.natappfree.cc/sc-site/order/return_url");// 前台跳转url
		origMap.put("Memo", Memo);

		// 4.2.1.1. 公众号/服务窗确认支付 api 业务参数
		origMap.put("OutTradeNo", OutTradeNo);//商户唯一订单号
		origMap.put("MchId", CHANPAY_PARTNER_ID); //商户标示ID
		origMap.put("SubMchId", "");  //子商户标示ID
		origMap.put("TradeType", "11"); //交易类型（即时 11 担保 12）
		origMap.put("BankCode", "WXPAY"); //银行编码 WXPAY:微信渠道		ALIPAY:支付宝渠道		UNIONPAY:银联渠道
		origMap.put("AppId", wx_appId);
		origMap.put("DeviceInfo", wx_appId);
		origMap.put("Currency", "CNY");
		origMap.put("TradeAmount", TradeAmount); //交易金额 交易金额（元）精确到小数点后两位
		origMap.put("EnsureAmount", ""); //担保金额 如果交易类型为12,担保金额必填，担保金额可以小于订单金额，订单金额减去担保金额为及时到账部分
		origMap.put("GoodsName", GoodsName); //商品名称
		origMap.put("TradeMemo", TradeMemo); //商品描述
		origMap.put("Subject",Subject); //订单标题
		origMap.put("OrderStartTime",OrderStartTime); //订单起始提交时间 订单生成时间，格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
		origMap.put("OrderEndTime", OrderEndTime); //订单结束时间 订单失效时间默认为5分钟，如要缩短失效时间需要上送,格式为yyyyMMddHHmmss，如2009年12月25日9点10分10秒表示为20091225091010
		origMap.put("NotifyUrl", notify_url); //服务器异步通知页面路径
		origMap.put("SpbillCreateIp", SpbillCreateIp); //终端IP
		origMap.put("SplitList", "");//分账列表 分账列表json格式		PayeeId：收方商户号		Amount：分账金额
		origMap.put("Ext", "{'ext':'ext1'}"); //扩展字段

		return gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
	}
	/**
	 * 4.2.1.4. api mag_init_code_pay 支付宝主扫预下单
	 */
	public static String  zfb_mag_init_code_pay(Map<String, String> origMap) {
		String notify_url = origMap.get("notify_url").toString();
		//String returnUrl = origMap.get("returnUrl").toString();
		String OutTradeNo = origMap.get("OutTradeNo").toString();
		String TradeAmount = origMap.get("TradeAmount").toString();
		String GoodsName = origMap.get("GoodsName").toString();
		String Memo = origMap.get("Memo").toString();
		String TradeMemo = origMap.get("TradeMemo").toString();
		String Subject = origMap.get("Subject").toString();
		String OrderStartTime = origMap.get("OrderStartTime").toString();
		String OrderEndTime = origMap.get("OrderEndTime").toString();
		String SpbillCreateIp = origMap.get("SpbillCreateIp").toString();
		Date date = new Date();
		// 基本参数
		origMap.put("Service", "mag_init_code_pay");
		origMap.put("Version", "1.0");
		origMap.put("PartnerId", CHANPAY_PARTNER_ID);//T环境
		origMap.put("InputCharset", charset);
		origMap.put("TradeDate", getDateFormat("yyyyMMdd").format(date));
		origMap.put("TradeTime", getDateFormat("HHmmss").format(date));
		// origMap.put("SignType","RSA");
		//origMap.put("ReturnUrl", returnUrl);// 前台跳转url
		origMap.put("Memo", Memo);

		// 4.2.1.1. 公众号/服务窗确认支付 api 业务参数
		origMap.put("OutTradeNo", OutTradeNo);//商户唯一订单号
		origMap.put("MchId", CHANPAY_PARTNER_ID);//商户标示ID
		origMap.put("SubMchId", "");  //子商户标示ID
		origMap.put("TradeType", "11"); //交易类型（即时 11 担保 12）
		origMap.put("BankCode", "ALIPAY"); //银行编码 WXPAY:微信渠道		ALIPAY:支付宝渠道		UNIONPAY:银联渠道
		origMap.put("AppId", zfb_appId);
		origMap.put("DeviceInfo", zfb_appId);
		origMap.put("Currency", "CNY");
		origMap.put("TradeAmount", TradeAmount);
		origMap.put("EnsureAmount", "");
		origMap.put("GoodsName",GoodsName);
		origMap.put("TradeMemo", TradeMemo);
		origMap.put("Subject",Subject);
		origMap.put("OrderStartTime",
				OrderStartTime);
		origMap.put("OrderEndTime", OrderEndTime);
		origMap.put("NotifyUrl", notify_url);
		origMap.put("SpbillCreateIp", SpbillCreateIp);
		origMap.put("SplitList", "");
		origMap.put("Ext", "{'ext':'ext1'}");

		return gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
	}
}
